<?php
declare (strict_types=1);

namespace app\common\logic;

use app\common\event\subscribes\notify\Notify as NotifyEvent;
use app\common\exception\LogicException;
use app\common\model\payment\{PaymentOrder as PO, PaymentOrderItem as POI, Transaction};
use app\common\model\ProductType;
use app\course\event\subscribes\course\Course as CourseEvent;
use app\course\logic\base\{Course, CourseSection, CourseStudent};
use app\mall\logic\product\ProductSale;
use app\promotion\logic\{Promotion, PromotionTuan, PromotionTuanData};
use app\school\logic\school\School;
use app\user\event\subscribes\user\Credit as CreditEvent;
use app\user\logic\teacher\Teacher;
use app\user\logic\user\{Account, Balance, BalanceFlow, Credit, CreditFlow, Split, SplitCourse, SplitFlow, VipUser};
use app\user\model\user\UserPaymentData;
use Exception;
use think\facade\{Db, Event};

class AfterPay
{
    // 队列处理支付状态、分成及明细等
    public function run($order_no)
    {
        Db::startTrans();
        try {
            // 订单信息
            $order = app(PO::class)->with(['itemMany'])->where('order_no', $order_no)->where('status', 10)->findOrEmpty();
            //
            if ($order->isEmpty()) return;
            //
            $products = Course::getCourseProducts();
            // 支付时间
            $payment_time        = app(Transaction::class)->where('order_no', $order->order_no)->value('payment_time');
            $order->payment_time = $payment_time;

            foreach ($order->itemMany as $item) {
                $course = in_array($item->product_type_id, $products);
                if ($course) {
                    // 处理拼团
                    $tuan = $this->handlePintuan($item);
                    if ('done' === $tuan['status']) {
                        // 订单状态
                        $order->status = 20;
                        // 处理成功入团订单
                        $this->handleSuccessTuan($tuan['tuan_id']);
                        // 处理未成功入团订单
                        $this->handleUnsuccessTuan($tuan['tuan_id'], $item->promotion_id);
                    } else if ('not' === $tuan['status']) {   // 无拼团
                        // 订单状态
                        $order->status = 20;
                        // 处理分成
                        $this->handleSplit($item, $payment_time);
                        // 加入course_student
                        $this->handleStudent($item);
                        // 余额充值、会员购买、积分充值等后续
                        $this->handleOthers($item);
                        // 积分抵扣（生成订单已抵扣）
                        // $this->handleCreditRedeem($item);
                    } else if ('nothing' === $tuan['status']) {
                        return;
                    } else if ('wait' === $tuan['status']) {
                        // 订单状态
                        $order->status = 80;
                    } else {
                        // 订单状态
                        $order->status = 20;
                    }
                    if (!$order->save()) throw new LogicException('操作失败');
                } else {
                    $order->status = 20;
                    if (!$order->save()) throw new LogicException('操作失败');
                    $this->handleOthers($item);
                }
            }
            // 订单量
            $order_count = $order->itemMany ? count($order->itemMany) : 0;

            if ($order_count) {
                $payment = app(UserPaymentData::class)->where('user_id', $order->user_id)->findOrEmpty();
                if (!$payment->isEmpty()) {
                    $payment->payment_count = Db::raw('payment_count+' . $order_count);
                    $payment->payment       = Db::raw('payment+' . $order->payment);
                } else {
                    $payment->user_id       = $order->user_id;
                    $payment->payment_count = $order_count;
                    $payment->payment       = $order->payment;
                }

                if (!$payment->save()) throw new LogicException('操作失败');
            }
            Db::commit();
        } catch (LogicException|Exception $e) {
            Db::rollback();
            throw new LogicException($e->getMessage());
        }
    }

    /**
     * 处理成功入团订单
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-05-07
     *
     * @param  [type] $mid     [description]
     * @param  [type] $tuan_id [description]
     */
    public function handleSuccessTuan($tuan_id)
    {
        // 获取非当前用户的所有团员订单
        $data = app(PromotionTuanData::class)->whereTuanId($tuan_id)->whereStatus(1)->select();

        foreach ($data as $v) {
            $order_item = app(POI::class)->with(['transaction_time'])->where('order_sub_no', $v->order_sub_no)->findOrEmpty();
            if (!$order_item->isEmpty()) {
                $order = app(PO::class)->where('order_no', $order_item->order_no)->findOrEmpty();
                //
                if (!$order->isEmpty()) {
                    $order->status = 20;
                    if (!$order->save()) throw new LogicException('操作失败');
                }
                // 处理分成
                $this->handleSplit($order_item, $order_item->payment_time ?? null);
                // 加入course_student
                $this->handleStudent($order_item);
                // 积分抵扣（生成订单已抵扣）
                // $this->handleCreditRedeem($item);
            }
        }
    }

    /**
     * 处理未成功入团订单
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-05-07
     *
     * @param  [type] $mid     [description]
     * @param  [type] $tuan_id [description]
     */
    public function handleUnsuccessTuan($tuan_id, $promotion_id)
    {
        // 获取非当前用户的所有团员订单
        $data = app(PromotionTuanData::class)->whereTuanId($tuan_id)->whereStatus(0)->select();
        foreach ($data as $v) {
            $order_item = app(POI::class)->whereUserId($v->user_id)->wherePromotionId($promotion_id)->findOrEmpty();
            if ($order_item->isEmpty()) continue;

            $order = app(PO::class)->where('order_no', $order_item->order_no)->findOrEmpty();
            if ($order->isEmpty()) continue;

            $order->status = 60;
            if (!$order->save()) throw new LogicException('操作失败');
        }
    }

    /**
     * 处理拼团 【拼团未完成，支付后不处理流水及学员，完成后处理所有】
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-04-14
     *
     * @param  [type] $item     [description]
     * @param  [type] $products [description]
     */
    public function handlePintuan($item): array
    {
        // 
        if (!$item->promotion_id) return ['status' => 'not'];
        //
        $type = app(Promotion::class)->getPromotionType($item->promotion_id);
        if (4 != $type) return ['status' => 'not'];
        //
        $promotion_id = $item->promotion_id;
        $tuan         = app(PromotionTuan::class)->promotionId($promotion_id)->userId($item->user_id)->order('id DESC')->findOrEmpty();
        if (!$tuan->isEmpty()) {
            $tuan->status = 1;
            if (!$tuan->save()) throw new LogicException('操作失败');
        }
        $tuan_sql  = app(PromotionTuanData::class)->alias('tuan_data')
            ->join('promotion_tuan tuan', '`tuan`.`id`=`tuan_data`.`tuan_id` AND `tuan`.`promotion_id`= ' . $promotion_id . ' AND `tuan_data`.`user_id`=' . $item->user_id . ' AND tuan_data.delete_time is null')->field('tuan_data.*')->buildSql();
        $tuan_data = Db::query($tuan_sql);
        if ($tuan_data) return ['status' => 'nothing'];

        $tuan_data = current($tuan_data);
        //
        $tuan_data               = app(PromotionTuanData::class)->findOrEmpty($tuan_data['id']);
        $tuan_data->status       = 1;
        $tuan_data->order_sub_no = $item->order_sub_no;
        //
        if (!$tuan_data->save()) throw new LogicException('操作失败');
        //
        $tuan = app(PromotionTuan::class)->findOrEmpty($tuan_data->tuan_id);
        if ($tuan->join_num + 1 == $tuan->total_num) $tuan->status = 2;
        $tuan->join_num += 1;
        if (!$tuan->save()) throw new LogicException('操作失败');
        // 未完成的拼团，不走分成、学员等
        if ($tuan->status == 2) return ['status' => 'done', 'tuan_id' => $tuan->id];
        return ['status' => 'wait'];
    }

    /**
     * 处理积分抵扣
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-08-26
     *
     * @param  [type] $item [description]
     */
    public function handleCreditRedeem($item)
    {
        // $item->credit && $item->credit->credit && app(Credit::class)->redeemCredit($credit['credit']);
    }

    // 处理分成
    public function handleSplit($item, $payment_time = null)
    {
        if (isset($item->ext_data->share)) {
            $eventData = [
                'user_id'   => $item->ext_data->share,
                'course_id' => $item->product_id,
                'rel_pk'    => $item->order_sub_no,
                'type'      => 'share',
            ];
            // Db::name('test')->save(['msg'=>json_encode($eventData)]);
            Event::subscribe(CourseEvent::class);
            Event::trigger('CourseShare', $eventData);
        }

        if ($item->payment < 0.06) return;
        $payment_time = $payment_time ?: time();
        // 购买课程课时进入分成
        // 给用户分成，分成收入计入余额，添加余额流水及冻结流水
        // 分成进入冻结金额，通过流水查询状态及时间，超过7天的取消冻结，转入收入，便可实现提现
        $section_id = $item->section_id ?: 0;
        $course_id  = $item->product_id;
        $course     = app(Course::class)->withTrashed()->findOrEmpty($item->product_id);
        //
        $mhm_id = $course->mhm_id ?: 0;
        // 分成比例
        $split_config   = SplitConfig::get($mhm_id);
        $teacher_id     = app(Teacher::class)->getTeacherUserId($course->teacher_id);
        $school_user_id = app(School::class)->getSchoolUserId($mhm_id);
        $course_title   = $course->title;
        $section_title  = app(CourseSection::class)->getSectionTitle($item->section_id);    // 不存在或非课时时为null
        $title          = $section_title ? $course_title . ' - ' . $section_title : $course_title;

        $school  = in_array($mhm_id, [0, 1]) ? 0 : ceil($split_config['school'] * $item->payment) / 100;
        $teacher = $teacher_id ? ceil($split_config['teacher'] * $item->payment) / 100 : 0;
        // 挂载机构和分享者
        $mount = isset($item->ext_data->mount) ? ceil($split_config['mount_school'] * $item->payment) / 100 : 0;
        $share = isset($item->ext_data->share) ? ceil($split_config['share'] * $item->payment) / 100 : 0;
        // 上下级 primary一级    secondary二级
        $primary   = isset($item->ext_data->primary) ? ceil($split_config['distributor_first'] * $item->payment) / 100 : 0;
        $secondary = isset($item->ext_data->secondary) ? ceil($split_config['distributor_second'] * $item->payment) / 100 : 0;
        bcscale(2);
        $platform = ($item->payment - $school - $teacher - $mount - $share - $primary - $secondary);
        $platform = bcsub($platform . '', '0');
        // 退款配置
        // $refundConfig = SystemConfig::get('refund.config', ['effective_days' => 0]);
        // $refundDays   = $refundConfig['effective_days'];
        $refundDays   = 7;
        $course_param = [
            'order_sub_no'           => $item->order_sub_no,
            'user_id'                => $item->user_id,
            'course_id'              => $course_id,
            'section_id'             => $section_id,
            'mhm_id'                 => $mhm_id,
            'payment'                => floatval($item->payment),
            'platform_sum'           => $platform,
            'school_user_id'         => $school_user_id,
            'school_sum'             => $school,
            'teacher_user_id'        => $teacher_id,
            'teacher_sum'            => $teacher,
            'mount_user_id'          => $item->ext_data->mount ?? 0,
            'mount_sum'              => $mount,
            'share_user_id'          => $item->ext_data->share ?? 0,
            'share_user_sum'         => $share,
            'primary_user_id'        => $item->ext_data->primary ?? 0,
            'primary_distribution'   => $primary,
            'secondary_user_id'      => $item->ext_data->secondary ?? 0,
            'secondary_distribution' => $secondary,
            'note'                   => ($section_title ? '购买课时《' : '购买课程《') . $title . '》的分成',
            'unfrozen_time'          => $payment_time + $refundDays * 86400
        ];
        $split_course = app(SplitCourse::class)::create($course_param);

        if (!$split_course->isEmpty()) {

            $rel_id = $split_course->id;

            if ($school && $school_user_id) $this->handleData($school_user_id, $school, $rel_id, '购买《' . $title . '》的机构分成', 51);
            if ($teacher && $teacher_id) $this->handleData($teacher_id, $teacher, $rel_id, '购买《' . $title . '》的讲师分成', 52);
            if ($mount && $item->ext_data->mount) $this->handleData($item->ext_data->mount, $mount, $rel_id, '购买《' . $title . '》的挂载分成', 53);
            if ($share && $item->ext_data->share) $this->handleData($item->ext_data->share, $share, $rel_id, '购买《' . $title . '》的分享分成', 54);
            if ($primary && $item->ext_data->primary) $this->handleData($item->ext_data->primary, $primary, $rel_id, '购买《' . $title . '》的一级分销分成', 55);
            if ($secondary && $item->ext_data->secondary) $this->handleData($item->ext_data->secondary, $secondary, $rel_id, '购买《' . $title . '》的二级分销分成', 56);
        }
    }

    // 分成及流水表
    public function handleData($user_id, $num, $rel_id, $note = '', $type = 5)
    {
        // split
        $user_mhm_id = app(Account::class)->getUserMhmId($user_id) ?: 0;

        $exist = app(Split::class)->where('user_id', $user_id)->findOrEmpty();
        if ($exist->isEmpty()) {
            $exist = app(Split::class)::create([
                'user_id' => $user_id,
                'mhm_id'  => $user_mhm_id,
                'amount'  => '0.00',
                'frozen'  => $num
            ]);
            if ($exist->isEmpty()) throw new LogicException('操作失败');
        } else {
            $exist->frozen += $num;
            if (!$exist->save()) throw new LogicException('操作失败');
        }
        // split_flow
        $flow = app(SplitFlow::class)::create([
            'user_id' => $user_id,
            'mhm_id'  => $user_mhm_id,
            'type'    => $type,
            'num'     => $num,
            'amount'  => $exist->amount,
            'frozen'  => $exist->frozen,
            'rel_id'  => $rel_id,
            'note'    => $note,
        ]);
        if ($flow->isEmpty()) throw new LogicException('操作失败');
    }

    // 课程添加到学员表
    public function handleStudent($item)
    {
        if ($item->section_id == 0) {
            // 下单时是否是会员
            $vip_user = app(VipUser::class)->where('user_id', $item->user_id)->where('expire_time', '>=', $item->create_time)->findOrEmpty();

            $from = $item->payment ? ($vip_user->isEmpty() ? 2 : 3) : ($vip_user->isEmpty() ? 4 : 5);
            $max  = app(CourseStudent::class)->whereUserId($item->user_id)->whereCourseId($item->product_id)->findOrEmpty();
            if ($max->isEmpty()) {
                $save = CourseStudent::create([
                    'user_id'     => $item->user_id,
                    'course_id'   => $item->product_id,
                    'from'        => $from, // 2:学员购买 3:会员购买
                    'create_time' => $item->create_time,
                    'expire_time' => $item->expire_time ?: null,
                    'buy_number'  => $max->isEmpty() ? 1 : $max->buy_number + 1,
                ]);
                if ($save->isEmpty()) throw new LogicException('操作失败');
            } else {
                $max->from        = $from;
                $max->create_time = $item->create_time;
                $max->expire_time = $item->expire_time;
                $max->buy_number  += 1;
                if (!$max->save()) throw new LogicException('操作失败');
            }
            // 积分与通知
            $course = app(Course::class)->field('title,teacher_id')->findOrEmpty($item->product_id);
            Event::subscribe(CourseEvent::class);
            Event::trigger('CoursePurchase', [
                'user_id'         => $item->user_id,
                'user_name'       => app(Account::class)->getUserNickName($item->user_id),
                'teacher_user_id' => app(Teacher::class)->getTeacherUserId($course->teacher_id),
                'teacher_name'    => app(Teacher::class)->getTeacherName($course->teacher_id),
                'course_id'       => $item->product_id,
                'course_title'    => $course->title,
                'rel_pk'          => $item->order_sub_no,
            ]);
        }
    }

    // 余额充值、会员购买、积分充值等后续
    public function handleOthers($item)
    {
        // 产品类型
        $_vip     = ProductType::getProductIdByKey('vip');
        $_balance = ProductType::getProductIdByKey('balance');
        $_credit  = ProductType::getProductIdByKey('credit');
        $_exam    = ProductType::getProductIdByKey('exam');
        $_goods   = ProductType::getProductIdByKey('goods');
        //

        switch ($item->product_type_id) {
            case $_vip:
                // 会员充值
                $vip_user = app(VipUser::class)->where('user_id', $item->user_id)->findOrEmpty();
                // 添加会员
                if ($vip_user->isEmpty()) {
                    $vip_user = app(VipUser::class)::create([
                        'user_id'     => $item->user_id,
                        'expire_time' => $item->expire_time,
                    ]);
                    // 未创建成功
                    if ($vip_user->isEmpty()) throw new LogicException('操作失败');
                } else {
                    $vip_user->expire_time = $item->expire_time;
                    if (!$vip_user->save()) throw new LogicException('操作失败');
                }
                // 通知
                $param = [
                    'user' => $item->user_id,
                    'type' => 'system_notify',
                    'key'  => 'vip_recharge',
                    'var'  => [
                        'user_name' => app(Account::class)->getUserNickName($item->user_id),
                    ],
                ];
                Event::subscribe(NotifyEvent::class);
                Event::trigger('Notify', $param);
                // 充值会员获得积分
                Event::subscribe(CreditEvent::class);
                Event::trigger('VipCredit', [
                    'rel_pk'  => $item->product_id,
                    'user_id' => $item->user_id
                ]);
                break;

            case $_balance:
                // 余额充值
                // 检查重复支付
                $exist = app(BalanceFlow::class)->where('rel_pk', $item->order_no)->findOrEmpty();
                if ($exist->isEmpty()) {
                    /* 参数说明【消费用户ID、余额消费类型、消费金额、消费关联表、关联表ID、消费备注】 */
                    app(Balance::class)->increaseUserBalance($item->user_id, 6, $item->original_price, 'payment_order', $item->order_no, '充值余额：' . $item->original_price);
                }
                // 通知
                $param = [
                    'user' => $item->user_id,
                    'type' => 'system_notify',
                    'key'  => 'balance_recharge',
                    'var'  => [
                        'user_name' => app(Account::class)->getUserNickName($item->user_id),
                        'money'     => $item->original_price,
                    ],
                ];

                Event::subscribe(NotifyEvent::class);
                Event::trigger('Notify', $param);

                break;

            case $_credit:
                // 积分充值
                // 检查重复支付
                $exist = app(CreditFlow::class)->where('rel_pk', $item->order_no)->findOrEmpty();

                if ($exist->isEmpty()) {
                    /* 参数说明【消费用户ID、流水类型、积分变动数额、消费关联表、关联表ID、消费备注】 */
                    app(Credit::class)->increaseUserCredit($item->user_id, 1, $item->original_price, 'recharge', $item->order_no, '充值积分：' . $item->original_price);
                }
                break;

            case $_exam:
                # code...
                break;

            case $_goods:
                // 增加销量
                /** @var ProductSale $sale */
                $sale = app(ProductSale::class);
                $sale->addProductSale($item->product_id, $item->user_id, $item->order_sub_no);
                break;

            default: // 1、2、3、4、5
                // 课程添加销售额
                if ($item->section_id == 0) {
                    $course = app(Course::class)->findOrEmpty($item->product_id);
                    if (!$course->isEmpty()) {
                        $course->sale_count += 1;
                        if (!$course->save()) throw new LogicException('操作失败');
                    }
                }
                break;
        }
    }

}
